#ifndef TFTP_SERVER_H_
#define TFTP_SERVER_H_

// we probably need much less. but this is a good start
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sstream>
#include <iostream>
#include <fstream>
#include <list>
#include <algorithm>
#include <map>
#include <time.h>

#define BUFFER_SIZE 2048
#define MAX_PATH 1024

#define PORT_NUMBER 6900

#define CONNECTION_SUCCESS 0
#define CONNECTION_ERROR -1
#define CONNECTION_ABORT_CURRENT -2
#define CONNECTION_RETRY -3
#define CONNECTION_UNEXPECTED_CLIENT -4
#define CONNECTION_TRANSMISSION_ENDED -5
#define CONNECTION_TRANSMISSION_ENDED_ABORT -6

#define TIMEOUT_SECONDS 2
#define TIMEOUT_BLOCK_RETRANSMIT_TRIES 10

#define OPCODE_RRQ 01
#define OPCODE_WRQ 02
#define OPCODE_DATA 03
#define OPCODE_ACK 04
#define OPCODE_ERROR 05

#define OPCODE_ACK_SIZE 4
#define OPCODE_REGULAR_ERROR_SIZE 5

#define ERROR_CODE_NOT_DEFINED 0
#define ERROR_CODE_FILE_NOT_FOUND 1
#define ERROR_CODE_ACCESS_VIOLATION 2
#define ERROR_CODE_DISK_FULL_OR_ALLOCATION_EXCEEDED 3
#define ERROR_CODE_ILLEGAL_TFTP_OPERATION 4
#define ERROR_CODE_UNKNOWN_TRANSFER_ID 5
#define ERROR_CODE_FILE_ALREADY_EXISTS 6
#define ERROR_CODE_NO_SUCH_USER 7

#define ERROR_MESSAGE_BLOCK_RETRANSMISSIONS_EXCEEDED "Block retransmissions exceeded"
#define ERROR_MESSAGE_UNSUPPORTED_MODE "Unsupported mode"
#define ERROR_MESSAGE_MALEFORMED "Maleformed message"

using namespace std;

typedef char byte;

struct Connection {
    int socket_descriptor;
    sockaddr_in client;
    uint16_t blockNumber;
    byte buff[BUFFER_SIZE];
    char filename[MAX_PATH];
    int errorCode;
};

// returns a socket
int init(Connection& connection);

int handler(Connection& connection);

void handleRead(Connection& connection);

void handleWrite(Connection& connection);

int handleUndefinedError(Connection& connection, string msg);

int handleError(Connection& connection, int messageLength);

int sendAck(Connection& connection);

int recieveData(Connection& connection, bool transmissionEnded, ofstream& writtenFile);

int timeoutSelect(Connection& connection);

#endif /* TFTP_SERVER_H_ */
